﻿#include<stdio.h>
#include<climits>


typedef char  * byte_pointer;

void show_Byte(byte_pointer start, size_t length)
{
	size_t i;
	for ( i = 0; i < length; i++)
	{
		printf("%.2x", start[i]);
	}
}

void show_short( short start)
{
	show_Byte((byte_pointer)&start, sizeof(short));
}

/*
编写过程 is_little_endian当在小端法机器上编译和运行时返回 1，在大端法机器上编译运行
时则返回 0。这个程序应该可以运行在任何机器上，无论机器的字长是多少。
*/
//通过byte_pointer 获取第一个地址所存储的字节
int is_little_endian()
{
	short a = 1; // Ox 0001
	byte_pointer bp = (byte_pointer)&a; //这个bp实际上是 01

	return bp == 0x01;
	//输出为1 

}

/*
编写一个 C 表达式，它生成一个字，由 x 的最低有效字节和 y 中剩下的字节组成。对于运算数 x
=0x89ABCDEF 和 y=0x76543210就得到 0x765432EF
*/
int generate_word(int x, int y)
{
	//通过 & 来获取 具体位数
	x = x & (0xff); //就取到了 x等于000000 EF
	y &= 0xffffff00; //这样y等于765432 00

	return x | y; //最后 |  printf("%#x",a) //表示0x这个前缀也打印出来

}
/*unsigned replace_byte (unsigned x, int i, unsigned char b);
以下示例，说明了这个函数该如何工作:
replace.byte(0x12345678, 2, OxAB) --> 0xl2AB5678
replace_byte(0x12345678, 0, OxAB) —> 0xl23456AB
*/

unsigned replace_byte(unsigned x, int i, unsigned char b)
{
	if (i < 0 || i > sizeof(x) - 1) return x;

	unsigned y = (b & 0xff) << (i << 3);//1个字节8bit 要移动8次
	x = x & ~(0xff << (i << 3));
	return x | y;
}

int get_msb(int x) //获取最高有效位
{
	int shift_val = (sizeof(int) - 1) << 3;

	int xright = x >> shift_val;

	return x & 0xff;
}



/*写一个 C 表达式，在下列描述的条件下产生 1，而在其他情况下得到 0。假设 x是 int类型。
A.x的任何位都等于 1。
B. x的任何位都等于 0。
C. x的最低有效字节中的位都等于 1。
D. x的最高有效字节中的位都等于 0。
代码应该遵循位级整数编码规则，另外还有一个限制，你不能使用相等（==)和不相等（！=)
测试*/
int generate_1(int x)
{
	return !(x ^ 0xffffffff) | !x | !(get_msb(x) ^ (0x00)) | !((x &(0xff)^(0xff)));
}
int int_shifts_are_arithmetic()
{
	//判断是否为算术右移
	int testnum = ~0;//生成全为1的int类型数 0xffffffff

	int shiftnum = testnum >> ((sizeof(int) - 1) << 3);//让其开始右移 若为算术右移，则高位补1 和原值是相等的

	return shiftnum == testnum;
}

/*将下面的 C 函数代码补充完整。函数 srl 用算术右移 来完成逻辑右移
他操作不包括右移或者除法。函数sra用逻辑右移来完成算术右移
操作不包括右移或者除法。可以通过计算 8*sizeof(int)来确定数据类型 int 中的位数 。位移
量是 的取值范围为 0〜 1。*/
unsigned sr1(unsigned x, int k) // 不会
{

}

/*
Return 1 when any odd bit of x equals 1; 0 otherwise.
Assume w=32 
*/
int any_odd_one(unsigned x) //任意奇数位为1 返回1
{
	//x&0xAAAAAAAA 就是保留所有奇数位的数字，而偶数位全部变为0
	// x只要有一位为 1 ，则上述结果不为0 ，！操作后（非0变为0,0变为1），也就是变为0，在非一次变为1
	return !!(x & 0xAAAAAAAA);
}

/*/* Return 1 when x contains an odd number of Is; 0 otherwise.
Assume w=32 */
int odd_ones(unsigned x)
{
	//判断x二进制1的个数是否为奇数 其实就是每个位进行 异或操作 右移 加异或即可完成
	x = x ^ (x << 1);
	x = x ^ (x << 2);
	x = x ^ (x << 4);
	x = x ^ (x << 8);
	x = x ^ (x << 16);

	return x & (1);

}
/*
* Generate mask indicating leftmost 1 in x. Assume w=32.
* For example, OxFFOO ~> 0x8000, and 0x6600 --> 0x4000.
* If x = 0, then return 0.
* 生成最高位1 的掩码
*/

int leftmost_one(unsigned x)
{
	x |= (x << 1);
	x |= (x << 2);
	x |= (x << 4);
	x |= (x << 8);
	x |= (x << 16);
	//经过这么一系列操作 x会变成0x000FFFFF ; 就是最高位1左边全为0 右边全为1
	// x即变为[0000 11111.....1]
	 //如x = x = 00010110 上述操作后 x = 000 11111 
	//然后再 右移1位 变为 0000 1111 在取反变为 111 1 0000 这个和 x& 即可得到 0001 0000即为掩码
	unsigned mask = ~(x << 1);



	return mask & x;



	/*想得到的解法
	unsigned y = 0x80000000;

	while (y)
	{
		if (x & y)
		{
			break;
		}
		else 
		{
			y >> 1; //y中最高位的1 往右移位
		}
	}

	//如果结果不为零，那么这个y就是x中最左边的那个1所表示的数了
	return y;
	*/
}


int  bad_int_size_is_32()
{
	int set_msb = 1 << 31;
	//int  beyond_msb = 1 << 32;

	/*当在 SUN SPARC 这样的 32 位机器上编译并运行时，这个过程返回的却是 0。下面的编译器
	信息给了我们一个问题的指示：
		warning : left shift count >= width of type


		 1<< 32 在某些 32bit 机器上 可能等于 0 也可能等于1
    */

	//好像就是你不能一次移动32 ,分开移位
	int beyond_msb = 1 << 15;
	beyond_msb <<= 15;
	beyond_msb <<= 2;


	return set_msb && !beyond_msb;
}
/*
* Mask with least signficant n bits set to 1
* Examples: n
* Assume 1 <= n <= w  
n = 6
—> 0x3F, n = 17
—> OxlFFFF
*/

int lower_one_mask(int n)  //该开始为0 把最低n个字节 变为 1 
{
	//让0xFFFFFFFF 直接右移 

	int w = sizeof(int) * 8; //总共这么多位

	return 0xFFFFFFFF << (w - n);
}

/*
* Do rotating left shift.
* Examples when x
* n=4 -> 0x23456781, n=20 -> 0x67812345
Assume 0 <* n < w
= 0x12345678 and w = 32:
*/
unsigned rotate_left(unsigned x, int n)
{
	//比如 10 010  w = 5 位 
	// 左移 2 变为 010 00 
	// 右移3 变为  000 10
	//2者 | 以下 变为 010 10 正好和原来的倒过来了
	int w = sizeof(unsigned) * 8;

	if (n == 0) return x;

	return x << n | (x >> (w - n)); //特别注意 n = 0 ； 因为 n = 0 ； 移动w次 = 32 是错误的最多31次
}

/*
* Return 1 when x can be represented
* number; 0 otherwise
* Assume 1 <» n <* w
as an n-bit, 2's-complement
*/
int fits_bits(int x, int n) //n位 2进制 补码能表示 x吗
{
	//n为补码能表示的范围为 [- 2^(n-1) , 2^(n-1) -1]
	// 最大值为 0,1111.. 最小值为 1.0000000...
	int min = 1 << (n - 1);
	int max = -(min) -1;
	return min <= x && x <= max;
}

/*要将 4 个有符号字节封
装成一个 32 位 unsigned一个字中的字节从 0(最低有效字节）编号到 3(最高有效字节）。 分配给
你的任务是：为一个使用补码运算和算术右移的机器编写一个具有如下原型的函数：
*/
/* Declaration of data type where 4 bytes are packed
into an unsigned */
typedef unsigned packed_t;
/* Extract byte from word. Return as signed integer */
//函数会抽取出指定的字节，再把它符号扩展为一个 32 位 int
int false_xbyte(packed_t word, int bytenum) //错误版本
{
	//从 word中提取 第bytenum 个字节
	//错在 word本身是无符号数，其最后一个字节和0xff 进行与 ，必然是个正数 ，无法表示int的负数
	return ( word >> (bytenum <<3)) & 0xff; //把所选字节移动到最低位

}

int correct_xbyte(packed_t word, int bytenum)
{
	/*
	* bytenum = 0;
	word 是 0x12345678，按位拆解为：0x12 0x34 0x56 0x78。小端法表示
移动字节 0 到最高位：0x12345678 << 24 -> 0x12000000。
然后 0x12000000 >> 24 -> 0x12，即返回 0x12（18
	*/
	int num = word << ((3 -bytenum) << 3); //把所选中的字节移动到最高位 即为0xx XX0000

	return num >> 24; //得到0x xx
}

/* Copy integer into buffer if space is available */
/* WARNING: The following code is buggy
//把一个整数复制到缓冲区中，只有当缓冲区空闲时才行

void copy_int(int val， void* buf, int maxbytes) //buggy 程序
{
	if (maxbytes - sizeof(val) >= 0)
		memcpy(buf, (void*)&val, sizeof(val));
}因为maxbytes 为int 而 sizeof 传回 一个无符号数
两者相减int自动转为无符号数
若是传入一个负数，会变成一个非常大的无符号数 ，导致判断一直成立 ，我建议把 maxbytes 使用unsigned类型。


*/ 
/* Addition that saturates to TMin

TMax */

int saturating_add(int x, int y) //当正溢出时，饱和加法返回 TMax, 负溢出时，返回TMin
{
	int  sum = x + y;

	int sig_mask = 0x80000000; // 就是0x80000000; //1 000 ....0 

	int pos_over = !(x & sig_mask) && !(y & sig_mask) && (sum & sig_mask); 
	int neg_over = (x & sig_mask) && (y & sig_mask) && !(sum & sig_mask);

	(pos_over && (sum = INT_MAX)) || (neg_over && (sum = sig_mask));

	return sum;

}
//判断补码加法是否溢出
int is_overflow(int x, int y)
{
	int sign = 0x80000000;
	int res = x + y;
	return (!(x & sign) && !(y & sign) && (res & sign) || (x & sign) && (y & sign) && !(res & sign));

}
	/* Determine whether arguments can be subtracted without overflow 
	如果计算 x - y 不溢出，这个函数就返回 1。
	*/
int tsub_ok(int x, int y)
{
	int z = (~y) + 1;
	return !(is_overflow(x, z));
}






